home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_08_05 / 8n05035a < prev    next >
Text File  |  1990-04-17  |  13KB  |  288 lines

  1. /*
  2. prb.c - Packetized Ring Buffer demonstration
  3.  
  4. (c) Copyright 1989, 1990 Martin J. Stitt
  5. */
  6.  
  7. #include <alloc.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10.  
  11. typedef unsigned char byte;
  12. typedef unsigned int word;
  13.  
  14. typedef struct {
  15.   word prb_totbytes;     /* define the ring buffer's size */
  16.   byte *prb_base;        /* ptr to base of buffer */
  17.   byte *prb_head;        /* head ptr - from which data is read */
  18.   byte *prb_tail;        /* tail ptr - at which data is written */
  19.   word prb_free;         /* amount of free space in the buffer */
  20.   word prb_eobofs;       /* offset of byte just past the eob */
  21.   byte prb_packets;      /* number of records in the buffer */
  22.   byte prb_use_rectype;  /* indicates use of two byte headers */
  23.   word prb_overflow;     /* indicates when a record is too large */
  24.   byte prb_max_dsize;    /* maximum size for record's data */
  25.   } prb_type;
  26.  
  27. /*- prb_init -----------------------------------------------------------
  28. entry parms:    ptr to a partially initialized prb structure
  29.         prb_base must point to an allocated buffer
  30.         prb_totbytes must be its size
  31.         prb_use_rectype must be assigned
  32. exit parms:    function return value != 0 when the last buffer
  33.         offset is 0xFFFF
  34. notes: call before writing and reading.  can recall later to flush the
  35. ring buffer.  can ignore return value on sucessive calls.
  36. ------------------------------------------------------------------------*/
  37. word prb_init(prb_type *b) {
  38.  
  39.   b->prb_head = b->prb_base;                 /* initialize the pointers */
  40.   b->prb_tail = b->prb_base;                 /* to flush the buffer */
  41.   b->prb_free = b->prb_totbytes;
  42.   b->prb_packets = 0;
  43.   b->prb_max_dsize = 255-1;                  /* -1 for the header byte */
  44.   if(b->prb_use_rectype) b->prb_max_dsize--; /* if using 2 byte header */
  45.   b->prb_overflow = 0;
  46.   b->prb_eobofs = (word) b->prb_base + b->prb_totbytes;
  47.   return((b->prb_eobofs == 0) ? 1 : 0);
  48.   }
  49.  
  50. /*- prb_write_data ---------------------------------------------------------
  51. entry parms:    ptr to buffer structure
  52.         ptr to caller's data, size of caller's data
  53.         record type code (ignored if prb_use_rectype == 0)
  54. exit parms:    function return value != 0 if overflow
  55. ------------------------------------------------------------------------*/
  56. word prb_write_data(prb_type *b, void *idata, byte dsize, byte rectype) {
  57.  
  58.   byte csize;                     /* data bytes to xfer */
  59.   byte psize;                     /* total packet size */
  60.   word block1;                    /* bytes before wrap of tail */
  61.   byte need_wrap;                 /* flags need for a 2 part xfer */
  62.   word adjust_head;               /* bytes to advance the head ptr */
  63.   word head2end;                  /* bytes before wrap of head */
  64.  
  65.   if(dsize == 0) return(1);       /* anything to insert? */
  66.   if(dsize > b->prb_max_dsize) return(1); /* don't allow oversized data */
  67.   psize = dsize+1;                /* +1 for the pkt size header byte */
  68.   if(b->prb_use_rectype) {        /* if using a record type */ 
  69.     psize++;                      /* account for header byte */
  70.     }
  71.   if(psize > b->prb_totbytes) {   /* if record too large for buffer */ 
  72.     if(psize < b->prb_overflow) { /* record overflow unless another */
  73.       b->prb_overflow = psize;    /* larger recorded */
  74.       }
  75.     return(1);                    /* indicate a problem */
  76.     }
  77.   while(psize > b->prb_free) {    /* while not enough free room */ 
  78.     b->prb_free += *b->prb_head;  /* adjust free to show deletion */
  79.     b->prb_packets--;             /* adjust accounting of pkts */
  80.     adjust_head = *b->prb_head;   /* fetch size of pkt to be deleted */
  81.     head2end = b->prb_eobofs - (word) b->prb_head; /* calc bytes till wrap */
  82.     if(adjust_head > head2end) {  /* will deletion involve a wrap? */ 
  83.       adjust_head -= head2end;    /* calc bytes in second portion */
  84.       b->prb_head = b->prb_base;  /* wrap around */
  85.       }
  86.     b->prb_head += adjust_head;   /* advance the head pointer */
  87.     if((word) b->prb_head == b->prb_eobofs) {  /* if pkt deleted just fit */ 
  88.       b->prb_head = b->prb_base;  /* need to wrap */
  89.       }
  90.     }
  91.   block1 = b->prb_eobofs - (word) b->prb_tail; /* calc size of 1st block */
  92.   b->prb_packets++;               /* update accounting of pkts */
  93.   b->prb_free -= psize;           /* update accounting of free space */
  94.   csize = psize-1;                /* sub 1 for pkt size header byte */
  95.   *(b->prb_tail++) = psize;       /* write header byte, advance tail */
  96.   need_wrap = 0;                  /* initialize flag */
  97.   if(psize > block1) {            /* if won't all fit in 1st block */ 
  98.     need_wrap = 1;                /* write remainder in 2nd block */
  99.     csize = block1-1;             /* -1 for header already written */
  100.     if(csize == 0) {              /* if block1 only had 1 byte */ 
  101.       b->prb_tail = b->prb_base;  /* do the wrap now */
  102.       need_wrap = 0;              /* don't need to wrap later */
  103.       csize = psize-1;            /* -1 for header already written */
  104.       }
  105.     }
  106.   if(b->prb_use_rectype) {        /* if type code to be inserted */ 
  107.     *(b->prb_tail++) = rectype;   /* insert it now and advance tail */
  108.     csize--;                      /* account for type code */
  109.     if(csize == 0) {              /* if block1 only had 2 bytes */ 
  110.       b->prb_tail = b->prb_base;  /* do the wrap now */
  111.       need_wrap = 0;              /* don't need to wrap later */
  112.       csize = psize-2;            /* account for 2 bytes in header */
  113.       }
  114.     }
  115.   memmove(b->prb_tail,idata,csize);     /* insert csize bytes into buffer */
  116.   b->prb_tail += csize;                 /* advance tail past new data */
  117.   if(need_wrap)    {                       /* if more data left to insert */ 
  118.     b->prb_tail = b->prb_base;          /* wrap the tail back around */
  119.     (byte) idata += csize;              /* advance the caller's pointer */
  120.     memmove(b->prb_tail,idata,(psize-block1)); /* insert the remaining data */
  121.     b->prb_tail += (psize-block1);
  122.     }
  123.   if(b->prb_eobofs == (word) b->prb_tail) { /* if blk went just up to end */ 
  124.     b->prb_tail = b->prb_base;              /* need to wrap tail back around */
  125.     }
  126.   return(0);                                /* indicate success */
  127.   }
  128.  
  129. /*- prb_read_rectype ---------------------------------------------------
  130. entry parms:    ptr to buffer structure
  131.         address of byte to receive rectype
  132. exit parms:    function return value is data size
  133.         0 means buffer is empty
  134.  
  135. notes: presumes all ring buffer records contain a rectype byte in 
  136. their header.  if the buffer is empty, the rectype value returned 
  137. will be garbage.
  138. ------------------------------------------------------------------------*/
  139. byte prb_read_rectype(prb_type *b, byte *rectype) {
  140.  
  141.   byte *tptr;                         /* local scratch pointer */
  142.  
  143.   if(b->prb_packets == 0) return(0);  /* anything in buffer? */
  144.   tptr = b->prb_head + 1;             /* point to the record type code */
  145.   if(b->prb_eobofs == (word) tptr) {  /* need to wrap to read */ 
  146.     tptr = b->prb_base;               /* the 2nd byte? */
  147.     }
  148.   *rectype = *tptr;                   /* transfer rectype to caller */
  149.   return(*b->prb_head-2);             /* return the record size */
  150.   }
  151.  
  152. /*- prb_read_data -----------------------------------------------------------
  153. entry parms:    ptr to buffer structure
  154.         address of buffer to receive record contents
  155. exit parms:    function return value is data size
  156.         0 means buffer is empty
  157.  
  158. notes: presumes caller has referenced any recorded rectype and has 
  159. supplied a pointer to a large enough buffer.  *prb_head can be
  160. referenced to verify the size requirement.
  161. ------------------------------------------------------------------------*/
  162. byte prb_read_data(prb_type *b, void *dest) {
  163.  
  164.   byte dsize;                       /* data bytes in packet */
  165.   byte csize;                       /* bytes to transfer */
  166.   byte rsize;                       /* bytes left when need 2 xfers */
  167.   word block1;                      /* bytes before wrap */
  168.  
  169.   if(b->prb_packets == 0) return(0); /* make sure buffer has data */
  170.   b->p